#pragma once
#include "../common/message.hpp"
#include "../common/net.hpp"

namespace RPC
{
    namespace server
    {
        enum class VType
        {
            BOOL = 0,
            INTEGRAL,
            NUMERIC,
            STRING,
            ARRAY,
            OBJECT
        };

        class ServiceDiscribe
        {
        public: 
            using ptr = std::shared_ptr<ServiceDiscribe>;
            using ServiceCallback = std::function<void(const Json::Value&, Json::Value&)>;
            using ParamsDescribe = std::pair<std::string, VType>;
            ServiceDiscribe(std::string&& mname, std::vector<ParamsDescribe>&& desc, VType vtype, 
                             ServiceCallback&& handler)
                :_method_name(std::move(mname))
                ,_params_desc(std::move(desc))
                ,_return_type(vtype)
                ,_callback(std::move(handler))
            {}

            const std::string& method() {return _method_name;};
            
            //针对受到的参数请求进行校验;
            bool paramCheck(const Json::Value& params)
            {
                //对参数进行校验, 是否存在和类型正确.
                for(auto& desc : _params_desc)
                {
                    if(params.isMember(desc.first) == false)
                    {
                        ELOG("参数完整性校验失败! %s 字段缺失! ", desc.first.c_str());
                        return false;
                    }

                    if(check(desc.second, params[desc.first]) == false)
                    {
                        ELOG("参数类型校验失败! %s ", desc.first.c_str());
                        return false;
                    }
                }
                return true;
            }

            bool call(const Json::Value& params, Json::Value& result)
            {
                _callback(params, result);
                if(rtypeCheck(result) == false)
                {
                    ELOG("回调函数中的响应信息校验失败! ");
                    return false;
                }
                return true;
            }

        
        private:
            bool rtypeCheck(const Json::Value& val)
            {
                return check(_return_type, val);
            }

            bool check(VType vtype, const Json::Value& val)
            {
                switch(vtype)
                {
                    case VType::BOOL       :   return val.isBool();
                    case VType::INTEGRAL   :   return val.isIntegral();
                    case VType::NUMERIC    :   return val.isNumeric();
                    case VType::STRING     :   return val.isString();
                    case VType::ARRAY      :   return val.isArray();
                    case VType::OBJECT     :   return val.isObject();
                }
                return false;
            }
        private:
            std::string _method_name;
            ServiceCallback _callback;
            std::vector<ParamsDescribe> _params_desc;//参数字段描述;
            VType _return_type;//返回值结果类型的描述;
        };

        class SDiscribeFactory
        {
        public:
            void setMethodName(const std::string& name)
            {
                _method_name = name;
            }

            void setReturnType(VType vtype)
            {
                _return_type = vtype;
            }

            void setParamsDesc(const std::string& pname, VType vtype)
            {
                _params_desc.push_back(ServiceDiscribe::ParamsDescribe(pname, vtype));
            }

            void setCallback(const ServiceDiscribe::ServiceCallback& cb)
            {
                _callback = cb;
            }

            ServiceDiscribe::ptr build()
            {
                return std::make_shared<ServiceDiscribe>(std::move(_method_name), 
                    std::move(_params_desc), _return_type, std::move(_callback));
            }

        private:
            std::string _method_name;
            ServiceDiscribe::ServiceCallback _callback;
            std::vector<ServiceDiscribe::ParamsDescribe> _params_desc;//参数字段描述;
            VType _return_type;//返回值结果类型的描述;
        };

        class ServiceManger
        {
        public:
            using ptr = std::shared_ptr<ServiceManger>;
            void insert(const ServiceDiscribe::ptr& desc)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                _service.insert(std::make_pair(desc->method(), desc));
            }

            ServiceDiscribe::ptr select(const std::string& method_name)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _service.find(method_name);
                if(it == _service.end())
                {
                    return  ServiceDiscribe::ptr();
                }
                return it->second;
            }

            void remove(const std::string& method_name)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                _service.erase(method_name);
            }
        private:
            std::mutex _mutex;
            std::unordered_map<std::string, ServiceDiscribe::ptr> _service;
        };

        class RpcRouter
        {
        public:
            using ptr = std::shared_ptr<RpcRouter>;
            RpcRouter()
                :_server_manager(std::make_shared<ServiceManger>())
            {}
            //
            void onRpcRequest(const BaseConnection::ptr& conn, RpcRequest::ptr& request)
            {
                //1.查询客户端请求方法的描述, 判断当前服务器是否可以提供对应服务.
                auto service = _server_manager->select(request->method());
                if(service.get() == nullptr)
                {
                    ELOG("%s 服务找不到! ", request->method().c_str());
                    return response(conn, request, Json::Value(), RCode::RCODE_NOT_FOUND_SERVICE);
                }
                //2.进行参数校验, 确定能否提供服务,
                if(service->paramCheck(request->params()) == false)
                {
                    ELOG("%s 参数校验失败! ", request->method().c_str());
                    return response(conn, request, Json::Value(), RCode::RCODE_INVALID_PARAMS);
                }
                //3.调用业务回调函数,进行处理;
                Json::Value result;
                bool ret = service->call(request->params(), result);
                if(ret == false)
                {
                    ELOG("%s 服务器内部错误! ", request->method().c_str());
                    return response(conn, request, Json::Value(), RCode::RCODE_INTERNAL_ERROR);
                }
                //4.处理完毕得到结果.
                return response(conn, request, result, RCode::RCODE_OK);
            }

            void registerMethod(const ServiceDiscribe::ptr& service)
            {
                return _server_manager->insert(service);
            }
            
        private:
            void response(const BaseConnection::ptr& conn,
                const RpcRequest::ptr& req, 
                const Json::Value& res, 
                RCode rcode)
            {
                auto msg = MessageFactory::create<RpcResponse>();
                msg->setId(req->rid());
                msg->setMType(RPC::MType::RSP_RPC);
                msg->setRCode(rcode);
                msg->setResult(res);
                conn->send(msg);
            }
            ServiceManger::ptr _server_manager;
        };
    }
}